package imse.team0.inventoryws;

import imse.team0.inventoryws.db.dal.InventoryQueryService;
import imse.team0.inventoryws.parameters.NotAvailableException;
import imse.team0.inventoryws.parameters.OrderBookStatus;
import imse.team0.orders.Order;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Eugen, 4/28/12 3:03 PM
 */

@javax.jws.WebService(
        serviceName = "WarehouseInventoryService",
        portName = "InventoryServicePort",
        targetNamespace = "http://inventoryws.team0.imse",
        endpointInterface = "imse.team0.inventoryws.IWarehouseWS"
)
public class WarehouseWS implements IWarehouseWS{

    private InventoryQueryService queryService = new InventoryQueryService();

    /*
    * Order book status has different meanings:
    *   - in bookOrder it can have 2 states: fulfilled or partial. In case of partial no item is actually allocated.
    *   - in replenishRequest it has only 1 state: fulfilled. Even if there are items with low inventory, we always allocated
    *     the items (because the business rules for the local inventory dictate so)
    * */

    public OrderBookStatus bookOrder(Order order) {
        List<String> ids = new ArrayList<String>();
        List<Integer> qtys = new ArrayList<Integer>();
        OrderBookStatus orderStatus = new OrderBookStatus();
        for (Order.OrderItem item : order.items){
            ids.add(item.itemId);
            qtys.add(item.quantity);
        }
        Map<String, Integer> lowInventoryItems = new HashMap<String, Integer>();
        try {
            lowInventoryItems = queryService.removeItems(ids, qtys);
            if (lowInventoryItems != null) // there are low inventory items in the database
            {
                if (lowInventoryItems.size() == ids.size())
                {
                    orderStatus.setStatus(OrderBookStatus.STATUS.EMPTY);
                    // TODO: probably need to include here all order items
                }
                else{
                    orderStatus.setStatus(OrderBookStatus.STATUS.PARTIAL);
                    OrderBookStatus.AvailableUnit unit = new OrderBookStatus.AvailableUnit();
                    for (String id : ids)
                    {
                        unit.setId(id);
                        unit.setRequested(qtys.get(ids.indexOf(id)));
                        if (lowInventoryItems.containsKey(id))
                        {
                            unit.setAvailable(lowInventoryItems.get(id));
                        }
                        else
                            unit.setAvailable(qtys.get(ids.indexOf(id)));
                        orderStatus.addUnit(unit);
                    }
                }
            }
            else {
                orderStatus.setStatus(OrderBookStatus.STATUS.FULFILLED);
                // TODO: think if need to insert all items in case of successful booking
            }
        } catch (Exception e) {
            orderStatus.setStatus(OrderBookStatus.STATUS.TEMPORARILY_UNAVAILABLE);
        }
        return orderStatus;
    }

    public OrderBookStatus replenishRequest(List<Order.OrderItem> replenishItems, String localInventoryID) throws NotAvailableException{
        /*Probably we can insert here some locking logic to block temporarily new incoming imse.team0.orders.orders
        * in favour of local inventory replenishment*/
        List<String> ids = new ArrayList<String>(replenishItems.size());
        List<Integer> qtys = new ArrayList<Integer>(replenishItems.size());
        for (Order.OrderItem item : replenishItems)
        {
            ids.add(item.itemId);
            qtys.add(item.quantity);
        }
        boolean replenishmentIsntCompleted = true;
        // make a copy of initially requested quantities
        List<Integer> requestedQTYs = new ArrayList<Integer>(qtys);
        while (replenishmentIsntCompleted)
        try {
            Map<String, Integer> availableQTYs = queryService.removeItems(ids, qtys);
            if (availableQTYs == null)
                break;
            else {
                for (String lowInventoryID : availableQTYs.keySet()){
                    int index = ids.indexOf(lowInventoryID);
                    qtys.set(index, availableQTYs.get(lowInventoryID));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            throw new NotAvailableException(e);
        }
        OrderBookStatus orderStatus = new OrderBookStatus();
        orderStatus.setStatus(OrderBookStatus.STATUS.FULFILLED);
        OrderBookStatus.AvailableUnit unit = new OrderBookStatus.AvailableUnit();
        for (int i = 0; i < ids.size(); i++)
        {
            unit.setId(ids.get(i));
            unit.setRequested(requestedQTYs.get(i));
            unit.setAvailable(qtys.get(i));
            orderStatus.addUnit(unit);
        }
        return orderStatus;
        /*also we might insert some other logic for performing the actual delivery given
        * the inventory ID (e.g. prepare a shipment job to the inventory's address)*/
    }
}
